/*=============================================================================
#     FileName: my_sock_lib.h
#         Desc: 封装了对socket各种属性进行设置的例程
#       Author: Ace
#        Email: goace@acm.org
#     HomePage: http://www.goace.co.cc
#      Version: 0.0.1
#   LastChange: 2011-05-13 16:03:55
#      History:
=============================================================================*/

#ifndef	MY_SOCK_LIB_H_
#define MY_SOCK_LIB_H_

#include  <sys/types.h>
#include  <sys/socket.h>
#include  <sys/time.h>
#include  <unistd.h>
#include  <stdio.h>
#include  <fcntl.h>
#include  <netinet/in.h>
#include  <netinet/tcp.h>

namespace ace
{
	//宏定义
	#define		TIMEOUT_SEC		1
	#define		TIMEOUT_USEC	1
	#define		READ			0x01
	#define		WRITE			0x02     

	#define     KEEP_IDLE		18		//发送心跳前的等待时间
	#define     KEEP_INTERVAL	5		//心跳的间隔时间
	#define     KEEP_COUNT		3		//判定对方掉线前的心跳包数目

	/* ---------------------------------------------------------------*/
	/**
	 * 函数简介:  对传入的fd设置超时
	 *
	 * 参数: fd	   要设置的fd
	 *
	 * 参数: flag  READ标记表示对读操作设置超时
	 *             WRITE标记表示对写操作设置超时
	 *  
	 * 返回值：0表示成功  -1表示失败
	 */
	/* ---------------------------------------------------------------*/
	inline int set_sock_timeo(int fd, uint8_t flag)
	{
		//初始化时间结构体
		struct timeval timeout;
		timeout.tv_sec	=	TIMEOUT_SEC;
		timeout.tv_usec =	TIMEOUT_USEC;

		int res;
		if( flag & READ) 
		{
			res = setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,
					&timeout,sizeof(timeout));
			if( res < 0 )
			{
				perror("set_sock_timeo");
				return -1;
			}
		}
		if( flag & WRITE )
		{
			res = setsockopt(fd,SOL_SOCKET,SO_SNDTIMEO,
					&timeout,sizeof(timeout));
			if( res < 0 )
			{
				perror("set_sock_timeo");
				return -1;
			}
		}

		return 0;
	}

	/* ---------------------------------------------------------------*/
	/**
	 * 函数简介:  开启指定fd的心跳功能
	 *
	 * 参数: fd	  需要开启的fd
	 *
	 * 返回值: 0表示成功  -1表示失败
	 */
	/* ---------------------------------------------------------------*/
	inline int setkeepalive(int fd)
	{
		int keep_alive	=	1;
		int keep_idle	=	KEEP_IDLE;
		int keep_int	=	KEEP_INTERVAL;
		int keep_count	=	KEEP_COUNT;

		int res;
	
		//开启keepalive
		res = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, 
				(void *)&keep_alive, sizeof(int));
		if( res < 0 )
		{
			perror("setkeepalive");
			return -1;
		}
		
		//设置发送心跳包之前允许对方socket沉默的时间
		res = setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, 
				(void*)&keep_idle, sizeof(int)); 
		if( res < 0 )
		{
			perror("setkeepalive");
			return -1;
		}
		
		//设置每个心跳包之间间隔的时间
		res = setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, 
				(void *)&keep_int, sizeof(int));
		if( res < 0 )
		{
			perror("setkeepalive");
			return -1;
		}
		
		//设置重发几次心跳包
		res = setsockopt(fd, SOL_TCP, TCP_KEEPCNT, 
				(void *)&keep_count, sizeof(int));
		if( res < 0 )
		{
			perror("setkeepalive");
			return -1;
		}

		return 0;
	}

	/* ---------------------------------------------------------------*/
	/**
	 * 函数简介:  把传入的fd设成阻塞
	 *
	 * 参数: sock 需要设置的fd
	 *
	 * 返回值: 0表示成功  -1表示失败
	 */
	/* ---------------------------------------------------------------*/
	inline int setblocking(int sock)
	{
		int opts;
		opts = fcntl(sock,F_GETFL);
		if(opts < 0)
		{
			perror("fcntl(sock,GETFL)");
			return -1;
		}
		
		opts = opts & !O_NONBLOCK;
		if(fcntl(sock,F_SETFL,opts) < 0)
		{
			perror("fcntl(sock,SETFL,opts)");
			return -1;
		}

		return 0;
	}

	/* ---------------------------------------------------------------*/
	/**
	 * 函数简介:  把传入的fd设成非阻塞
	 *
	 * 参数: sock 需要设置的fd
	 *
	 * 返回值: 0表示成功  -1表示失败
	 */
	/* ---------------------------------------------------------------*/
	inline int setnonblocking(int sock)
	{
		int opts;

		opts = fcntl(sock,F_GETFL);
		if(opts<0)
		{
			perror("fcntl(sock,GETFL)");
			return -1;
		}

		opts = opts|O_NONBLOCK;
		if(fcntl(sock,F_SETFL,opts)<0)
		{
			perror("fcntl(sock,SETFL,opts)");
			return -1;
		}

		return 0;
	}
}

#endif
